package com.kamistoat.ruoyi.ruoyiauth.service;

import com.kamistoat.ruoyi.ruoyiapisystem.domain.SysUser;
import com.kamistoat.ruoyi.ruoyicommoncore.constant.CacheConstants;
import com.kamistoat.ruoyi.ruoyicommoncore.constant.Constants;
import com.kamistoat.ruoyi.ruoyicommoncore.exception.ServiceException;
import com.kamistoat.ruoyi.ruoyicommoncore.utils.StringUtils;
import com.kamistoat.ruoyi.ruoyicommonredis.utils.RedissonUtils;
import com.kamistoat.ruoyi.ruoyicommonsecurity.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 登录密码服务。该服务会在已经根据前端输入的用户名从数据库中找到了对应的SysUser
 */
@Component
public class SysPasswordService {
    @Autowired
    RedissonUtils redissonUtils;
    @Autowired
    SysRecordLogService sysRecordLogService;

    // 最大重试次数
    private final int maxRetryCount = CacheConstants.passwordMaxRetryCount;
    // 锁定时间
    private final Long lockTime = CacheConstants.passwordLockTime;

    /**
     * 获取密码错误重试次数的缓存键名
     *
     * @param username 用户名
     * @return 拼接结果
     */
    private String getPWD_ERR_CNT_KEY(String username) {
        return CacheConstants.PWD_ERR_CNT_KEY + username;
    }

    /**
     * 验证密码
     *
     * @param sysUser  前端用户名对应的 sysUser
     * @param password 前端密码
     */
    public void validate(SysUser sysUser, String password) throws ServiceException {
        String username = sysUser.getUserName();

        // 检查是否已经达到重试次数上限
        Integer retryCount = (Integer) redissonUtils.getCacheObject(getPWD_ERR_CNT_KEY(username));
        retryCount = StringUtils.isNull(retryCount) ? 0 : retryCount;
        if (retryCount >= maxRetryCount) {
            String errMsg = String.format("密码输入错误%s次，账户锁定%s分钟", maxRetryCount, lockTime);
            sysRecordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, errMsg);
            throw new ServiceException(errMsg);
        }

        // 密码匹配
        if (!matchPassword(sysUser, password)) {
            retryCount++;
            String errMsg = String.format("密码输入错误%s次，还可再尝试%s次", retryCount, maxRetryCount - retryCount);
            sysRecordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, errMsg);
            redissonUtils.setCacheObject(getPWD_ERR_CNT_KEY(username), retryCount, lockTime, TimeUnit.MINUTES);
            throw new ServiceException("用户不存在/密码错误");
        } else {
            clearLoginRecordCache(username);
        }
    }

    /**
     * 验证密码是否匹配
     *
     * @param sysUser     前端用户名对应的SysUser
     * @param rawPassword 前端密码
     * @return
     */
    private boolean matchPassword(SysUser sysUser, String rawPassword) {
        return SecurityUtils.matchesPassword(rawPassword, sysUser.getPassword());
    }

    /**
     * 清除密码重试缓存
     *
     * @param username 前端用户名
     */
    private void clearLoginRecordCache(String username) {
        Object cacheObject = redissonUtils.getCacheObject(getPWD_ERR_CNT_KEY(username));
        if (StringUtils.isNotNull(cacheObject)) {
            redissonUtils.deleteObject(getPWD_ERR_CNT_KEY(username));
        }
    }


}
